#include "util.hpp"
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>

class ServerTcp
{
public:
    ServerTcp(uint16_t port, const std::string &ip = "") : port_(port), ip_(ip), listenSock_(-1)
    {
    }
    ~ServerTcp()
    {
    }

public:
    void init()
    {
        // 1. 创建socket
        listenSock_ = socket(PF_INET, SOCK_STREAM, 0);
        if (listenSock_ < 0)
        {
            logMessage(FATAL, "socket: %s", strerror(errno));
            exit(SOCKET_ERR);
        }
        logMessage(DEBUG, "socket: %s, %d", strerror(errno), listenSock_);

        // 2. bind绑定
        // 2.1 填充服务器信息
        struct sockaddr_in local; // 用户栈
        memset(&local, 0, sizeof local);
        local.sin_family = PF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));
        // 2.2 本地socket信息，写入sock_对应的内核区域
        if (bind(listenSock_, (const struct sockaddr *)&local, sizeof local) < 0)
        {
            logMessage(FATAL, "bind: %s", strerror(errno));
            exit(BIND_ERR);
        }
        logMessage(DEBUG, "bind: %s, %d", strerror(errno), listenSock_);

        // 3. 监听socket，为何要监听呢？tcp是面向连接的！
        if (listen(listenSock_, 5 /*后面再说*/) < 0)
        {
            logMessage(FATAL, "listen: %s", strerror(errno));
            exit(LISTEN_ERR);
        }
        logMessage(DEBUG, "listen: %s, %d", strerror(errno), listenSock_);
        // 运行别人来连接你了
    }
    void loop()
    {
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            // 4. 获取连接, accept 的返回值是一个新的socket fd ？？
            int serviceSock = accept(listenSock_, (struct sockaddr *)&peer, &len);
            if (serviceSock < 0)
            {
                // 获取链接失败
                logMessage(WARINING, "accept: %s[%d]", strerror(errno), serviceSock);
                continue;
            }

            //4.1获取客户端信息
            uint16_t peerPort = ntohs(peer.sin_port);
            std::string peerIp = inet_ntoa(peer.sin_addr);
            
             logMessage(DEBUG, "accept: %s | %s[%d], socket fd: %d",
                       strerror(errno), peerIp.c_str(), peerPort, serviceSock);


            //5 提供服务版本 echo 服务
            transService(serviceSock,peerIp,peerPort);


            // logMessage(DEBUG, "server 提供 service start ...");
            // sleep(1);
        }
    }

    void transService(int sock,const std::string &clientIp,uint16_t clientPort)
    {
        assert(sock >= 0);
        assert(!clientIp.empty());
        assert(clientPort >= 1024);

        char inbuffer[BUFFER_SIZE];
        while(true)
        {
            ssize_t s = read(sock,inbuffer,sizeof(inbuffer) - 1);
            if(s > 0)
            {
                inbuffer[s] = '\0';
                if(strcasecmp(inbuffer,"quit") == 0)
                {
                    logMessage(DEBUG,"client quit -- %s[%d]", clientIp.c_str(), clientPort);
                    break;
                }

                for(int i = 0; i < s; i++)
                {
                    if(isalpha(inbuffer[i]) && islower(inbuffer[i]))
                    { 
                        inbuffer[i] = toupper(inbuffer[i]);
                    }
                }
                logMessage(DEBUG, "trans after: %s[%d]>>> %s", clientIp.c_str(), clientPort, inbuffer);

                write(sock, inbuffer, strlen(inbuffer));             
            }
            else if(s == 0)
            {
                // pipe: 读端一直在读，写端不写了，并且关闭了写端，读端会如何？s == 0，代表对端关闭
                // s == 0: 代表对方关闭,client 退出
                logMessage(DEBUG, "client quit -- %s[%d]", clientIp.c_str(), clientPort);
                break;
            }
        }

    }

private:
  // sock
    int listenSock_;
    // port
    uint16_t port_;
    // ip
    std::string ip_;
};

static void Usage(std::string proc)
{
    std::cerr << "Usage:\n\t" << proc << " port ip" << std::endl;
    std::cerr << "example:\n\t" << proc << " 8080 127.0.0.1\n" << std::endl;
}


int main(int argc,char *argv[])
{
    if(argc != 3 && argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    } 

    uint16_t port = atoi(argv[1]);
    std::string ip;
    if(argc == 3)
    {
        ip = argv[2];
    }

    ServerTcp svr(port,ip);
    svr.init();
    svr.loop();
    return 0;
}